﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Xml.Serialization;

namespace d39
{
    [Serializable]
    public class TerrainType
    {
        [XmlAttribute("difficult")]
        public bool IsDifficult { get; set; }

        [XmlIgnore]
        public Color Color { get; set; }

        [XmlAttribute("color")]
        public string ColorString
        {
            get { return ColorTranslator.ToHtml(Color); }
            set { Color = ColorTranslator.FromHtml(value); }
        }

        [XmlAttribute("perimeter")]
        public int PerimeterThickness { get; set; }

        [XmlIgnore]
        public Color PerimeterColor { get; set; }

        [XmlAttribute("perimeter-color")]
        public string PerimeterColorString
        {
            get { return ColorTranslator.ToHtml(PerimeterColor); }
            set { PerimeterColor = ColorTranslator.FromHtml(value); }
        }

        [XmlAttribute("perimeter-style")]
        public DashStyle PerimeterDashStyle { get; set; }

        [XmlAttribute("opacity")]
        public int Opacity { get; set; }

        [XmlAttribute("name")]
        public string Description { get; set; }

        [XmlElement("area")]
        public List<Segment> Segments { get; set; }

        public TerrainType()
        {
            Color = Color.FromArgb(0, 0, 0);
            PerimeterColor = Color.FromArgb(0, 0, 0);
            PerimeterDashStyle = DashStyle.Solid;
            Segments = new List<Segment>();
            Opacity = 10;
        }

        [XmlIgnore]
        public Color ColorWithOpacity
        {
            get { return Color.FromArgb((Opacity * 255) / 10, Color); }
        }

        [XmlIgnore]
        public Color PerimeterColorWithOpacity
        {
            get { return Color.FromArgb((Opacity * 255) / 10, PerimeterColor); }
        }

        [XmlIgnore]
        public string CssStyle
        {
            get
            {
                var result = "background-color: " + ColorTranslator.ToHtml(Color) +
                    "; color:" + ColorTranslator.ToHtml(Color.GetContrastColor()) + "; border: " + PerimeterThickness + "px ";
                if (PerimeterDashStyle == DashStyle.Dash)
                {
                    result += "dashed";
                }
                else if (PerimeterDashStyle == DashStyle.Dot)
                {
                    result += "dotted";
                }
                else
                {
                    result += "solid";
                }
                return result + ColorTranslator.ToHtml(PerimeterColor);
            }
        }

        [XmlIgnore]
        public string SegmentsString
        {
            get { return Segments.ToHumanReadableString(); }
            set { Segments = d39.Segments.ParseHumanReadableSegments(value); }
        }

        // The format is:
        // OX000000T111111ss.ss-D
        // X = X for difficult terrain, omitted otherwise
        // 000000 = Color
        // T111111P (optional) - perimeter thickness and color. Perimeter thickness is between 1 and 4; if a number is not in that location, then both the
        // thickness and color are omitted. P is either omitted, 8 (dashed) or 9 (dotted).
        // ss = list of segments to the perimeter
        // D = description, optional
        public static TerrainType FromString(string str)
        {
            var result = new TerrainType();
            int end = 0;
            if (str[end] == 'X')
            {
                result.IsDifficult = true;
                end++;
            }
            if (str[end] >= 'G' && str[end] <= 'Q')
            {
                result.Opacity = (int)str[end++] - (int)'G';
            }
            result.Color = ColorTranslator.FromHtml('#' + str.Substring(end, 6));
            end += 6;
            if (end < str.Length && str[end] >= '1' && str[end] <= '4')
            {
                result.PerimeterThickness = int.Parse(str.Substring(end, 1));
                result.PerimeterColor = ColorTranslator.FromHtml('#' + str.Substring(end + 1, 6));
                end += 7;
                if (end < str.Length && (str[end] == '8' || str[end] == '9'))
                {
                    result.PerimeterDashStyle = (str[end] == '8' ? DashStyle.Dash : DashStyle.Dot);
                    end++;
                }
            }
            var descrStart = str.IndexOf('-', end);
            if (descrStart >= 0)
            {
                result.Description = str.Substring(descrStart + 1);
            }
            else
            {
                descrStart = str.Length;
            }
            result.Segments = d39.Segments.ParseSegments(str.Substring(end, descrStart - end));
            return result;
        }
        public string ToString(UrlTweaks tweaks)
        {
            var includeDescription = tweaks.IncludeDescriptions;
            if (string.IsNullOrEmpty(Description)) includeDescription = false;
            var start = IsDifficult ? "X" : "";
            if (Opacity < 10) start += (char)((int)'G' + Opacity);
            start += ColorTranslator.ToHtml(Color).Substring(1);
            if (PerimeterThickness != 0)
            {
                start += PerimeterThickness + ColorTranslator.ToHtml(PerimeterColor).Substring(1);
                if (PerimeterDashStyle == DashStyle.Dash) start += '8';
                if (PerimeterDashStyle == DashStyle.Dot) start += '9';
            }
            start += Segments.ToSegmentString();
            return includeDescription ? start + "-" + Description : start;
        }
    }
}